/* Copyright (c) 2009 Christopher Humphries, Maxime Simon
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package data;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

import history.Caretaker;
import history.Originator;

/**
 * @author Humphries Christopher - Simon Maxime
 * 
 */
public class Buffer {

    private Clipboard m_clipboard;
    private StringBuffer m_text;
    private Originator m_historyOriginator;
    private Caretaker m_historyCaretaker;

    /**
     * @param start
     * @param end
     * @return
     */
    public String read(int start, int end) {
	if (end > m_text.length())
	    end = m_text.length();

	if (start > end) {
	    int temp = start;
	    start = end;
	    end = temp;
	} // fun!

	return m_text.substring(start, end);
    }

    /**
     * @return
     */
    public String read() {
	return read(0, m_text.length());
    }

    /**
     * @param text
     * @param start
     * @param end
     * @return
     */
    public boolean write(String text, int start, int end) {
	if (end > m_text.length())
	    end = m_text.length();

	if (start < 0)
	    start = 0;

	if (start > end) {
	    int temp = start;
	    start = end;
	    end = temp;
	} // fun!

	m_historyOriginator.setAfter(text);
	m_historyOriginator.setStart(start);
	m_historyOriginator.setEnd(end);

	if (start == end) {
	    m_historyOriginator.setBefore("");
	    m_text.insert(start, text);
	} else {
	    m_historyOriginator.setBefore(read(start, end));
	    m_text.replace(start, end, text);
	}

	m_historyCaretaker.addMemento(m_historyOriginator.saveToMemento());

	System.out.println("\n" + m_text);

	return true;
    }

    /**
     * @param c
     * @param start
     * @param end
     * @return
     */
    public boolean write(char c, int start, int end) {
	return write(Character.toString(c), start, end);
    }

    /**
     * @param before
     * @param after
     * @param start
     * @param end
     * @return
     */
    public boolean storeMemento(String before, String after, int start, int end) {
	m_historyOriginator.setBefore(before);
	m_historyOriginator.setAfter(after);
	m_historyOriginator.setStart(start);
	m_historyOriginator.setEnd(end);

	m_historyCaretaker.addMemento(m_historyOriginator.saveToMemento());

	return true;
    }

    /**
     * @param index
     * @return
     */
    public boolean undoMemento(int index) {
	m_historyOriginator.restoreFromMemento(m_historyCaretaker.getMemento(index));

	if (m_historyOriginator.getStart() == m_historyOriginator.getEnd()) {
	    try {
		m_text.replace(m_historyOriginator.getStart(),
			m_historyOriginator.getStart()
				+ m_historyOriginator.getAfter().length(), "");
	    } catch (Exception e) {
		System.out.println("BUF:1:" + e);
	    }
	} else {
	    try {
		m_text.replace(m_historyOriginator.getStart(),
			m_historyOriginator.getStart()
				+ m_historyOriginator.getAfter().length(),
			m_historyOriginator.getBefore());
	    } catch (Exception e) {
		System.out.println("BUF:2:" + e);
	    }
	}

	return true;
    }

    /**
     * @param index
     * @return
     */
    public boolean restoreMemento(int index) {
	m_historyOriginator.restoreFromMemento(m_historyCaretaker.getMemento(index));

	if (m_historyOriginator.getStart() == m_historyOriginator.getEnd()) {
	    System.out.print("i");
	    try {
		m_text.insert(m_historyOriginator.getStart(),
			m_historyOriginator.getAfter());
	    } catch (Exception e) {
		System.out.println("BUF:3:" + e);
	    }
	} else {
	    System.out.print("r");
	    try {
		m_text.replace(m_historyOriginator.getStart(),
			m_historyOriginator.getEnd(),
			m_historyOriginator.getAfter());
	    } catch (Exception e) {
		System.out.println("BUF:4:" + e);
	    }
	}

	// System.out.println("\n" + m_text);

	return true;
    }

    /**
     * @param filename
     * @throws IOException
     */
    public void loadFile(String filename) throws IOException {
	String lineSeperator = System.getProperty("line.separator");

	BufferedReader bufferedReader = new BufferedReader(new FileReader(
		filename));

	String nextLine = "";

	StringBuffer stringBuffer = new StringBuffer();

	while ((nextLine = bufferedReader.readLine()) != null) {
	    stringBuffer.append(nextLine);
	    stringBuffer.append(lineSeperator);
	}

	m_historyCaretaker.reset();
	write(stringBuffer.toString(), 0, m_text.length());
	m_text = new StringBuffer(stringBuffer);
    }

    /**
     * 
     */
    public void reset() {
	m_historyCaretaker.reset();
	write("", 0, m_text.length());
    }

    /**
     * @param filename
     * @throws IOException
     */
    public void saveFile(String filename) throws IOException {
	Writer output = new BufferedWriter(new FileWriter(new File(filename)));
	try {
	    output.write(m_text.toString());
	} finally {
	    output.close();
	}
    }

    /**
     * @param start
     * @param end
     * @param keep
     * @return
     */
    public boolean store(int start, int end, boolean keep) {
	if (end > m_text.length())
	    end = m_text.length();

	if (start < 0)
	    start = 0;

	if (start > end) {
	    int temp = start;
	    start = end;
	    end = temp;
	} // fun!

	if (start != end) {
	    m_clipboard.write(read(start, end));

	    if (!keep) {
		write("", start, end);
	    }
	}

	return true;
    }

    /**
     * @return
     */
    public String retrieve() {
	return m_clipboard.read();
    }

    /**
     * @param caretaker
     * @param originator
     */
    public Buffer(Caretaker caretaker, Originator originator) {
	m_historyCaretaker = caretaker;
	m_historyOriginator = originator;
	m_clipboard = new Clipboard();
	m_text = new StringBuffer();
	write("The quick brown fox jumps over the lazy dog.", 0, 0);
    }
}
